package com.yuyou.fn.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.github.wens.mybatisplus.plugins.Page;
import com.github.wens.mybatisplus.toolkit.IdWorker;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.yuyou.fn.common.constant.ClassLevelEnum;
import com.yuyou.fn.common.constant.SysResourceEnum;
import com.yuyou.fn.common.exception.BusException;
import com.yuyou.fn.common.service.ISiteConfigService;
import com.yuyou.fn.common.util.*;
import com.yuyou.fn.datadeal.service.IStudentMergeService;
import com.yuyou.fn.educational.entity.*;
import com.yuyou.fn.educational.service.*;
import com.yuyou.fn.educational.vo.*;
import com.yuyou.fn.platform.permission.DataPermission;
import com.yuyou.fn.platform.service.ISysRoleResourceService;
import com.yuyou.fn.platform.service.ISysUserRoleService;
import com.yuyou.fn.report.entity.StudentRegDetail;
import com.yuyou.fn.report.service.IMergeStudentRegDetailService;
import com.yuyou.fn.report.service.IStudentRegDetailService;
import com.yuyou.fn.report.vo.StudentRegsDetailVo;
import com.yuyou.fn.settlement.entity.MainAccount;
import com.yuyou.fn.settlement.service.IPosPayService;
import com.yuyou.fn.settlement.service.ISettlementService;
import com.yuyou.fn.util.Webs;
import com.yuyou.fn.vo.AttendClassVo;
import com.yuyou.fn.vo.DiscountOffPolicyVo;
import com.yuyou.fn.vo.StudentClassCertDetailVo;
import com.yuyou.fn.vo.StudentRefundWithRegInfoDetailVo;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Created by Terry on 2017/3/7.
 *
 * @author Terry AdminEnrollApiController 报名
 */
@Controller
@RequestMapping("/api/admin")
public class AdminEnrollApiController extends ApiBaseController {

    private final static Logger log = LoggerFactory.getLogger(AdminEnrollApiController.class);

    public final static Multimap<String, DeferredResult<String>> deferredResultMultimap = ArrayListMultimap.create();

    @Resource
    private IStudentRegService studentRegService;


    @Resource
    private IStudentRefundService studentRefundService;

    @Resource
    private ICourseClassService courseClassService;

    @Resource
    private ICourseOrderService courseOrderService;

    @Resource
    private ISettlementService settlementService;

    @Resource
    private ICampusService campusService;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Resource
    private IClassLectureService classLectureService;

    @Resource
    private IAttendClassRecordService attendClassRecordService;


    @Resource
    private IDiscountService discountService;

    @Resource
    private IDiscountRuleService discountRuleService;

    @Resource
    private IShiftClassRecordService shiftClassRecordService;


    @Resource
    private IMergeStudentRegDetailService mergeStudentRegDetailService;

    @Resource
    private IStudentRegDetailService studentRegDetailService;

    @Resource
    private IStudentService studentService;

    @Resource
    private IStudentMergeService studentMergeService;

    @Resource
    private ICourseOrderDiscountService courseOrderDiscountService;

    @Resource
    private IPosPayService posPayService;

    @Resource
    private ISysRoleResourceService sysRoleResourceService;

    @Resource
    private ISysUserRoleService sysUserRoleService;

    @Resource
    private IRefundSettingService refundSettingService;

    @Resource
    private ISiteConfigService siteConfigService;

    @ApiOperation("报名班级列表")
    @RequestMapping(value = "/courseClassForReg", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<Page<CourseClass>> courseClassForReg(@ModelAttribute CourseClassQueryVo courseClassQueryVo, @RequestParam(value = "pageNo", defaultValue = "1") int pageNo, @RequestParam(value = "pageSize", defaultValue = "20") int pageSize, HttpServletRequest request) {
        Page<CourseClass> page = courseClassService.findCourseClassForRegByQueryForPage(courseClassQueryVo, pageNo, pageSize);
        return ReturnResult.success(page);
    }

    /**
     * 查询学生是否存在
     *
     * @param
     * @return
     */
    @ApiOperation("通过电话号码/名字/手机查询学生是否存在")
    @RequestMapping(value = "/searchStudent", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<Page<Student>> searchStudent(@RequestParam("keyword") String keyword, @RequestParam(value = "pageNo", defaultValue = "1") int pageNo, @RequestParam(value = "pageSize", defaultValue = "20") int pageSize, HttpServletRequest request) {
        Page<Student> studentList = studentService.findStudentByKeyword(keyword, pageNo, pageSize);
        return ReturnResult.success(studentList);
    }

    @ApiOperation("相同学生姓名(排除自己)")
    @RequestMapping(value = "/findStudentBySameName", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<Page<Student>> findStudentByName(@RequestParam("studentId")long studentId, HttpServletRequest request) {
        List<Student> studentList=studentService.findStudentBySameName(studentId);
        return ReturnResult.success(studentList);
    }


    @ApiOperation("合并学生")
    @RequestMapping(value = "/mergeStudent", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<Page<Student>> searchStudent(@RequestParam("originStudentId") long originStudentId, @RequestParam(value = "targetStudentId") long targetStudentId,@RequestParam(value = "cid",required = false)String cid, HttpServletRequest request) throws Exception {
        Student orignStudent=studentService.findById(originStudentId);
        Student targetStudent=studentService.findById(targetStudentId);
        if (!orignStudent.getName().equals(targetStudent.getName())){
            throw new BusException("姓名不一样不可合并");
        }
        if (StringUtils.isEmpty(cid)){
            cid=targetStudent.getCid();
        }
        studentMergeService.mergeStudentToAnother(originStudentId,targetStudentId,cid);
        return ReturnResult.success("ok");
    }


    /**
     * 增加学生信息
     *
     * @param studentSaveOrUpdateVo
     * @return
     */
    @ApiOperation("增加或者修改学生信息")
    @RequestMapping(value = "/saveOrUpdateStudent", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<Void> saveOrUpdateStudent(StudentSaveOrUpdateVo studentSaveOrUpdateVo, @RequestParam("guardianJsonStr") String guardianJsonStr) {
        List<StudentGuardianSaveOrUpdateVo> guardianList = JSON.parseObject(guardianJsonStr, new TypeReference<List<StudentGuardianSaveOrUpdateVo>>() {
        });
        studentSaveOrUpdateVo.setGuardianList(guardianList);
        Long studentId = studentService.saveOrUpdateStudent(studentSaveOrUpdateVo);
        return ReturnResult.success(studentId);
    }


    @ApiOperation("获取学生详细信息")
    @RequestMapping(value = "/studentDetail", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<StudentDetailVo> getStudentDetail(@RequestParam("studentId") Long studentId) {
        StudentDetailVo studentDetail = studentService.findStudentDetailByStudentId(studentId);
        return ReturnResult.success(studentDetail);
    }

    @ApiOperation("查询更多学生信息")
    @RequestMapping(value = "/findMoreStudentInfo", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<String> findMoreStudentInfo(HttpServletRequest request,
                                    HttpServletResponse response,
                                    @RequestParam("studentName") String studentName,
                                    @RequestParam("phone") String phone) {
        String domain = siteConfigService.getConfigValueFromCache("bigdata_domain");
        String accesKeyId = siteConfigService.getConfigValueFromCache("bigdata_accesskey_id");
        String accesskeySecret = siteConfigService.getConfigValueFromCache("bigdata_accesskey_secret");
        String version = siteConfigService.getConfigValueFromCache("bigdata_backend_vesion");
        //10位时间戳
        long timeStamp = new Date().getTime() / 1000;
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("accesskey_id", accesKeyId);
        paramsMap.put("accesskey_secret", accesskeySecret);
        paramsMap.put("version", version);
        paramsMap.put("phone", phone);
        paramsMap.put("student_name", studentName);
        paramsMap.put("timestamp", timeStamp);
        String URL = ZYBigDataSignatureUtils.getURL(domain, paramsMap);

        return new ReturnResult(true, "处理成功" , URL);
    }

    /**
     * 订单
     *
     * @param studentId
     * @param pageNo
     * @param pageSize
     * @return
     */
    @ApiOperation("学生订单列表")
    @RequestMapping(value = "/courseOrderList", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<Page<CourseOrder>> courseOrderList(@RequestParam(value = "studentId") Long studentId, @RequestParam(value = "pageNo", defaultValue = "1") int pageNo, @RequestParam(value = "pageSize", defaultValue = "20") int pageSize, HttpServletRequest request) {
        Page<CourseOrder> page = courseOrderService.findStudentEffectiveCourseOrderList(studentId, pageNo, pageSize);
        return ReturnResult.success(page);
    }


    @ApiOperation("创建报名订单")
    @RequestMapping(value = "/createOfflineOrder", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<CourseOrder> createOfflineOrder(@RequestParam("studentRegInfoJsonStr") String studentRegInfoJsonStr, HttpServletRequest request) {

        StudentRegInfoVo studentRegInfoVo = JSONObject.parseObject(studentRegInfoJsonStr, StudentRegInfoVo.class);
        Principals.Principal principal = getCurrentSysPrincipal();
        studentRegInfoVo.setFrom(0);// 线下
        CourseOrder courseOrder = courseOrderService.createUnOnlineOrder(studentRegInfoVo, principal);
        return ReturnResult.success(courseOrder);
    }

    @ApiOperation("添加订单优惠")
    @RequestMapping(value = "/addCourseOrderDiscount", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<CourseOrder> addCourseOrderDiscount(@RequestParam("courseOrderId") Long courseOrderId, @Valid ApplyDiscountVo applyDiscountVo) {
        courseOrderService.addCourseOrderDiscount(courseOrderId, applyDiscountVo);
        return ReturnResult.success("OK");
    }

    @ApiOperation("获取订单优惠")
    @RequestMapping(value = "/courseOrderDiscount", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<List<CourseOrderDiscount>> courseOrderDiscount(@RequestParam("courseOrderId") Long courseOrderId) {
        return ReturnResult.success(courseOrderDiscountService.findByCourseOrderIds(Arrays.asList(courseOrderId)));
    }

    @ApiOperation("删除订单优惠")
    @RequestMapping(value = "/delCourseOrderDiscount", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<CourseOrder> delCourseOrderDiscount(@RequestParam("courseOrderId") Long courseOrderId, @RequestParam(name = "discountId") Long discountId) {
        courseOrderService.delCourseOrderDiscount(courseOrderId, discountId);
        return ReturnResult.success("OK");
    }

    @ApiOperation("获取政策优惠")
    @RequestMapping(value = "/discountListOfPolicy", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<List<DiscountOffPolicyVo>> discountListOfPolicy(@RequestParam("areaTeamId") Long areaTeamId) {
        List<Discount> discountList = discountService.findDiscountOfEffectivePolicy(areaTeamId);
        List<Long> discountRuleIds = BeanUtils.toList(discountList, "discountRuleId");
        List<DiscountRule> discountRules = discountRuleService.findByIds(discountRuleIds);
        Map<Long, DiscountRule> discountRuleId2DiscountRule = BeanUtils.toMap(discountRules, "discountRuleId");
        List<DiscountOffPolicyVo> discountOffPolicyVos = new ArrayList<>(discountList.size());
        for (Discount discount : discountList) {
            DiscountOffPolicyVo discountOffPolicyVo = new DiscountOffPolicyVo();
            BeanUtils.copyProperties(discountOffPolicyVo, discount);
            discountOffPolicyVo.setInputParams(discountRuleId2DiscountRule.get(discount.getDiscountRuleId()).getInputParams());
            discountOffPolicyVos.add(discountOffPolicyVo);
        }
        return ReturnResult.success(discountOffPolicyVos);
    }


    /**
     * 在读班级信息
     *
     * @param studentId
     * @return
     */
    @ApiOperation("在读班级信息")
    @RequestMapping(value = "/studentReadClassList", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    private ReturnResult<List<StudentRegDetailVo>> studentReadClassList(@ModelAttribute StudentRegQueryVo studentRegQueryVo, @RequestParam(value = "studentId") Long studentId) {
        studentRegQueryVo.setStudentId(studentId);
        studentRegQueryVo.setRegStatus(0);
        List<StudentReg> studentRegList = studentRegService.findStudentRegQuery(studentRegQueryVo);
        List<StudentRegDetailVo> regDetailVoList = studentRegService.toStudentRegDetailVo(studentRegList);
        // 根据期id查询出该期的退费设置
        List<RefundSetting> refundSettings = refundSettingService.queryRefundSettings(studentRegQueryVo.getAreaTeamId(), studentRegQueryVo.getPeriodId());
        for (StudentRegDetailVo studentRegDetailVo : regDetailVoList) {
            studentRegDetailVo.setCanRefund(canRefund(refundSettings, studentRegDetailVo));
        }
        return ReturnResult.success(regDetailVoList);
    }


    @ApiOperation("根据手机号或者studentId查询报读信息在读班级信息")
    @RequestMapping(value = "/studentReadClassListByPhoneNoOrId", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    private ReturnResult<List<StudentRegDetailVo>> studentReadClassListByPhoneNo(@ModelAttribute StudentRegQueryVo studentRegQueryVo,@RequestParam(value = "studentPhoneNo",required = false) String studentPhoneNo) {
        if (studentRegQueryVo.getStudentId()==null){
            Student student=studentService.findByStudentNo(studentPhoneNo);
            if (student==null){
                return ReturnResult.success(Collections.EMPTY_LIST);
            }
            studentRegQueryVo.setStudentId(student.getStudentId());
        }
        studentRegQueryVo.setRegStatus(0);
        List<StudentReg> studentRegList = studentRegService.findStudentRegQuery(studentRegQueryVo);
        List<StudentRegDetailVo> regDetailVoList = studentRegService.toStudentRegDetailVo(studentRegList);
        // 根据期id查询出该期的退费设置
        List<RefundSetting> refundSettings = refundSettingService.queryRefundSettings(studentRegQueryVo.getAreaTeamId(), studentRegQueryVo.getPeriodId());
        for (StudentRegDetailVo studentRegDetailVo : regDetailVoList) {
            studentRegDetailVo.setCanRefund(canRefund(refundSettings, studentRegDetailVo));
        }
        return ReturnResult.success(regDetailVoList);
    }

    private boolean canRefund(List<RefundSetting> refundSettings, StudentRegDetailVo studentRegDetailVo) {
        boolean canRefund = true;
        Long studentRegPeriodId = studentRegDetailVo.getStudentReg().getPeriodId();
        Long studentRegBusTeamId = studentRegDetailVo.getStudentReg().getBusTeamId();
        Long studentRegGradeId = studentRegDetailVo.getCourseClass().getGradeId();
        for (RefundSetting refundSetting : refundSettings) {
            if (refundSetting.getPeriodId().equals(studentRegPeriodId) &&
                    refundSetting.getBusTeamId().equals(studentRegBusTeamId) &&
                    refundSetting.getGradeIds().contains(String.valueOf(studentRegGradeId))) {
                canRefund = false;
                return canRefund;
            }
        }
        return canRefund;
    }

    @ApiOperation("课程订单详情")
    @RequestMapping(value = "/courseOrderDetail", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    private ReturnResult<CourseOrderDetailVo> courseOrderDetail(@RequestParam(value = "courseOrderId") Long courseOrderId) {

        CourseOrderDetailVo vo = getCourseOrderDetailVo(courseOrderId);

        return ReturnResult.success(vo);
    }

    private CourseOrderDetailVo getCourseOrderDetailVo(@RequestParam(value = "courseOrderId") Long courseOrderId) {
        CourseOrder courseOrder = courseOrderService.findById(courseOrderId);
        List<StudentReg> studentRegList = studentRegService.findStudentRegByCourseOrderId(courseOrderId);
        List<Long> classIds = BeanUtils.toList(studentRegList, "classId");
        List<CourseClass> courseClassList = courseClassService.findByIds(classIds);
        Map<Long, CourseClass> courseClassMap = BeanUtils.toMap(courseClassList, "classId");

        List<StudentRegDetailVo> regDetailVoList = new ArrayList<>(studentRegList.size());

        for (StudentReg studentReg : studentRegList) {
            StudentRegDetailVo studentRegDetailVo = new StudentRegDetailVo(studentReg, courseClassMap.get(studentReg.getClassId()));
            regDetailVoList.add(studentRegDetailVo);
        }

        CourseOrderDetailVo vo = new CourseOrderDetailVo();
        vo.setCourseOrder(courseOrder);
        vo.setRegDetailVos(regDetailVoList);
        return vo;
    }

    @ApiOperation("学生听课证详情")
    @RequestMapping(value = "/studentClassCertDetail", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    private ReturnResult<StudentClassCertDetailVo> studentClassCertDetail(@RequestParam(value = "courseOrderId") Long courseOrderId, HttpServletRequest request) {
        CourseOrderDetailVo courseOrderDetailVo = getCourseOrderDetailVo(courseOrderId);
        StudentClassCertDetailVo studentClassCertDetailVo = new StudentClassCertDetailVo();
        BeanUtils.copyProperties(studentClassCertDetailVo, courseOrderDetailVo);
        studentClassCertDetailVo.setStudent(studentService.findById(courseOrderDetailVo.getCourseOrder().getStudentId()));
        studentClassCertDetailVo.setCampus(campusService.findById(courseOrderDetailVo.getRegDetailVos().get(0).getCourseClass().getCampusId()));

        studentClassCertDetailVo.setPrincipal(getUser(request).getRealName());

        return ReturnResult.success(studentClassCertDetailVo);
    }


    @ApiOperation("确认缴费")
    @RequestMapping(value = "/confirmPayOrder")
    @ResponseBody
    public ReturnResult<Long> confirmPayOrder(@RequestBody @Valid ConfirmPayInfo confirmPayInfo) {
        Long requestPayId = IdWorker.getId();
        confirmPayInfo.setRequestPayId(requestPayId);
        confirmPayInfo.setPrincipal(getCurrentSysPrincipal());
        courseOrderService.confirmPayOrderForOffline(confirmPayInfo);
        return ReturnResult.success(requestPayId);
    }

    @ApiOperation("撤销订单")
    @RequestMapping(value = "/cancelCourseOrder")
    @ResponseBody
    public ReturnResult<Void> cancelCourseOrder(@RequestParam("courseOrderId") Long courseOrderId, HttpServletRequest request) {
        courseOrderService.cancel(courseOrderId, getCurrentSysPrincipal());
        return ReturnResult.success("ok");
    }

    @ApiOperation("获取报名详情")
    @RequestMapping(value = "/studentRegDetail")
    @ResponseBody
    public ReturnResult<StudentRegDetailVo> studentRegDetail(@RequestParam(value = "regId") Long regId) {
        StudentReg studentReg = studentRegService.findById(regId);
        CourseClass courseClass = courseClassService.findById(studentReg.getClassId());
        return ReturnResult.success(new StudentRegDetailVo(studentReg, courseClass));
    }

    @ApiOperation("获取多个报名详情")
    @RequestMapping(value = "/studentRegDetails")
    @ResponseBody
    public ReturnResult<List<StudentRegDetailVo>> studentRegDetails(@RequestParam(value = "regIds")List<Long> regIds) {
        List<StudentReg> studentRegList=studentRegService.findByIds(regIds);
        List<Long> classIds = Utils.unique(BeanUtils.toList(studentRegList, "classId"));
        List<CourseClass> courseClassList=courseClassService.findByIds(classIds);
        Map<Long, CourseClass> classMap = BeanUtils.toMap(courseClassList, "classId");
        List<StudentRegDetailVo> studentRegDetailVoList=new ArrayList<>(studentRegList.size());
        for (StudentReg studentReg:studentRegList){
            studentRegDetailVoList.add(new StudentRegDetailVo(studentReg, classMap.get(studentReg.getClassId())));
        }
        return ReturnResult.success(studentRegDetailVoList);
    }


    @ApiOperation("确定转班")
    @RequestMapping(value = "/turnClass")
    @ResponseBody
    public ReturnResult<Void> turnClass(@RequestParam("regId") Long regId, @RequestParam("changeLectureFrom") Integer changeLectureFrom, @RequestParam("classId") Long classId, @RequestParam("startAmount") Integer startAmount, @RequestParam("endAmount") Integer endAmount, @RequestParam(value = "reason", required = false) String reason) {
        studentRegService.changeClass(regId, changeLectureFrom, classId, startAmount, endAmount, reason, Principals.get());
        return ReturnResult.success("ok");
    }


    @ApiOperation("退款申请列表")
    @RequestMapping("/showStudentRefundList")
    @ResponseBody
    public ReturnResult<Page<StudentRefund>> showStudentRefundList(StudentRefundQueryVo studentRefundQueryVo, @RequestParam(value = "pageNo", defaultValue = "1") int pageNo, @RequestParam(value = "pageSize", defaultValue = "20") int pageSize, HttpServletRequest request) {
        DataPermission dataPermission = getDataPermission(request);

        Page<StudentRefund> page = studentRefundService.findStudentRefundList(studentRefundQueryVo, dataPermission, pageNo, pageSize);
        return ReturnResult.success(page);
    }

    @ApiOperation("退款申请详情")
    @RequestMapping(value = "/studentRefundDetail", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<StudentRefund> studentRefundDetail(@RequestParam("studentRefundId") Long studentRefundId) {
        StudentRefund studentRefund = studentRefundService.findById(studentRefundId);
        return ReturnResult.success(studentRefund);
    }

    @ApiOperation("退款申请详情(包含原课程信息、发票信息)")
    @RequestMapping(value = "/studentRefundWithRegInfoDetail", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<StudentRefundWithRegInfoDetailVo> studentRefundWithRegInfoDetail(@RequestParam("studentRefundId") Long studentRefundId) {
        StudentRefund studentRefund = studentRefundService.findById(studentRefundId);
        CourseClass courseClass = courseClassService.findById(studentRefund.getClassId());
        StudentReg studentReg = studentRegService.findById(studentRefund.getStudentRegId());
        Student student = studentService.findById(studentReg.getStudentId());
        StudentRefundWithRegInfoDetailVo studentRefundWithRegInfoDetailVo = new StudentRefundWithRegInfoDetailVo();
        studentRefundWithRegInfoDetailVo.setCourseClass(courseClass);
        studentRefundWithRegInfoDetailVo.setStudentRefund(studentRefund);
        studentRefundWithRegInfoDetailVo.setStudentReg(studentReg);
        studentRefundWithRegInfoDetailVo.setStudent(student);
        return ReturnResult.success(studentRefundWithRegInfoDetailVo);
    }

    @ApiOperation("多个退款申请详情(包含原课程信息、发票信息)")
    @RequestMapping(value = "/studentRefundsWithRegInfoDetails", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<StudentRefundWithRegInfoDetailVo> studentRefundsWithRegInfoDetails(@RequestParam("studentRefundIds") List<Long> studentRefundIds) {
        List<StudentRefund> studentRefunds=studentRefundService.findByIds(studentRefundIds);
        List<StudentRefundWithRegInfoDetailVo> studentRefundWithRegInfoDetailVoList=new ArrayList<>(studentRefunds.size());

        List<Long> classIds = Utils.unique(BeanUtils.toList(studentRefunds, "classId"));
        List<CourseClass> courseClassList=courseClassService.findByIds(classIds);
        Map<Long, CourseClass> classMap = BeanUtils.toMap(courseClassList, "classId");

        List<Long> regIds=Utils.unique(BeanUtils.toList(studentRefunds,"studentRegId"));
        List<StudentReg> studentRegList=studentRegService.findByIds(regIds);
        Map<Long,StudentReg> studentRegMap=BeanUtils.toMap(studentRegList,"regId");

        List<Long> studentIds = BeanUtils.toList(studentRefunds, "studentId");
        List<Student> studentList=studentService.findByIds(studentIds);
        Map<Long, Student> studentMap = BeanUtils.toMap(studentList, "studentId");

        for (StudentRefund studentRefund:studentRefunds){
            CourseClass courseClass = classMap.get(studentRefund.getClassId());
            StudentReg studentReg = studentRegMap.get(studentRefund.getStudentRegId());
            Student student = studentMap.get(studentRefund.getStudentId());
            StudentRefundWithRegInfoDetailVo studentRefundWithRegInfoDetailVo = new StudentRefundWithRegInfoDetailVo();
            studentRefundWithRegInfoDetailVo.setCourseClass(courseClass);
            studentRefundWithRegInfoDetailVo.setStudentRefund(studentRefund);
            studentRefundWithRegInfoDetailVo.setStudentReg(studentReg);
            studentRefundWithRegInfoDetailVo.setStudent(student);
            studentRefundWithRegInfoDetailVoList.add(studentRefundWithRegInfoDetailVo);
        }

        return ReturnResult.success(studentRefundWithRegInfoDetailVoList);
    }


    @ApiOperation("创建退款申请")
    @RequestMapping("/saveStudentRefundClass")
    @ResponseBody
    public ReturnResult<Void> saveStudentRefundClass(StudentRefundVo studentRefundSaveOrUpdateVo, HttpServletRequest request) {
        StudentRefund studentRefund = studentRefundService.saveStudentRefund(studentRefundSaveOrUpdateVo, getCurrentSysPrincipal());
        return ReturnResult.success(studentRefund.getStudentRefundId());
    }

    @ApiOperation("批量退款申请")
    @RequestMapping(value = "/saveStudentRefundClassList", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<Void> saveStudentRefundClass(@Valid @RequestBody StudentRefundsVo studentRefundsVo, HttpServletRequest request) {
        List<RefundLectureDetailVo> refundLectureDetailVoList=studentRefundsVo.getRefundLectureDetailVos();
        List<StudentRefundVo> studentRefundVoList=new ArrayList<>(refundLectureDetailVoList.size());
        for (RefundLectureDetailVo  refundLectureDetailVo:refundLectureDetailVoList){
            StudentRefundVo studentRefundVo=new StudentRefundVo();
            BeanUtils.copyProperties(studentRefundVo,studentRefundsVo);
            BeanUtils.copyProperties(studentRefundVo,refundLectureDetailVo);
            studentRefundVoList.add(studentRefundVo);
        }
        List<StudentRefund> studentRefunds = studentRefundService.saveStudentRefundList(studentRefundVoList, getCurrentSysPrincipal());
        return ReturnResult.success(studentRefunds);
    }

    @ApiOperation("修改退款申请")
    @RequestMapping("/changeStudentRefundStatus")
    @ResponseBody
    public ReturnResult<Void> changeStudentRefundStatus(@RequestParam("studentRefundId") Long studentRefundId, @RequestParam("status") Integer status, @RequestParam("returnResult") String returnResult, HttpServletRequest request) {
        studentRefundService.changeStatus(studentRefundId, status, returnResult, getCurrentSysPrincipal());
        return ReturnResult.success("OK");
    }

    @ApiOperation("删除退款申请记录")
    @RequestMapping(value = "/delStudentRefund", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<Void> delStudentRefund(@RequestParam(value = "studentRefundId") Long studentRefundId) {
        studentRefundService.deleteStudentRefund(studentRefundId);
        return ReturnResult.success("Ok");
    }

    @ApiOperation("更改退款付款状态")
    @RequestMapping(value = "/changeStudentPayStatus", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<Void> changeStudentPayStatus(@RequestParam(value = "studentRefundId") Long studentRefundId, HttpServletRequest request) {
        studentRefundService.changeStudentPayStatus(studentRefundId, getUser(request).getUsername());
        return ReturnResult.success("Ok");
    }


    @ApiOperation("班级历史")
    @RequestMapping(value = "/classHistoryList", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<List<ClassHistoryListVo>> classHistoryList(@RequestParam(value = "regStatus", required = false) Integer regStatus, @RequestParam(value = "studentId") Long studentId) {
        StudentRegQueryVo studentRegQueryVo = new StudentRegQueryVo();
        studentRegQueryVo.setStudentId(studentId);
        if (regStatus != null) {
            studentRegQueryVo.setRegStatus(regStatus);
        }
        List<StudentReg> studentRegList = studentRegService.findStudentRegQuery(studentRegQueryVo);
        List<StudentRegDetailVo> regDetailVoList = studentRegService.toStudentRegDetailVo(studentRegList);
        return ReturnResult.success(regDetailVoList);
    }


    @ApiOperation("报名列表")
    @RequestMapping(value = "/studentRegList", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<Void> studentRegList(HttpServletRequest request, StudentRegQueryVo studentRegQueryVo, @RequestParam(value = "pageNo", defaultValue = "1") int pageNo, @RequestParam(value = "pageSize", defaultValue = "20") int pageSize) {
        DataPermission dataPermission = this.getDataPermission(request);
        Page<StudentRegDetail> newPage = studentRegDetailService.findStudentRegByPermissionQuery(dataPermission, studentRegQueryVo, pageNo, pageSize);
        return ReturnResult.success(newPage);
    }


    @ApiOperation("学生主账户")
    @RequestMapping(value = "/studentMainAccount", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<MainAccount> studentMainAccount(@RequestParam("studentId") Long studentId) {
        MainAccount mainAccount = settlementService.findMainAccount(studentId);
        return ReturnResult.success(mainAccount);
    }

    @ApiOperation("导出学生退费信息")
    @RequestMapping(value = "/exportStudentRefund", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<Void> exportStudentRefund(StudentRefundQueryVo studentRefundQueryVo, HttpServletRequest request, HttpServletResponse response) {

        if (studentRefundQueryVo.getEndAuditTime() != null) {
            studentRefundQueryVo.setEndAuditTime(TimeUtils.changeOneDateLastTime(studentRefundQueryVo.getEndAuditTime()));
        }
        if (studentRefundQueryVo.getEndPayTime() != null) {
            studentRefundQueryVo.setEndPayTime(TimeUtils.changeOneDateLastTime(studentRefundQueryVo.getEndPayTime()));
        }
        if (studentRefundQueryVo.getEndCreateTime() != null) {
            studentRefundQueryVo.setEndCreateTime(TimeUtils.changeOneDateLastTime(studentRefundQueryVo.getEndCreateTime()));
        }

        DataPermission dataPermission = getDataPermission(request);
        response.reset();
        response.setContentType("application/msexcel");
        response.setHeader("Content-Disposition", "attachment;Filename=" + "studentRefund" + TimeUtils.date2String(new Date(), "yyyyMMddHHmmss") + ".xlsx");
        response.addHeader("Access-Control-Allow-Origin", "*");
        OutputStream os = null;
        Workbook excel = studentRefundService.exportStudentRefund(studentRefundQueryVo, dataPermission);
        try {
            os = response.getOutputStream();
            excel.write(os);
        } catch (IOException e1) {
            log.error("学生退费导出出错", e1);
            return ReturnResult.fail("fail");
        } finally {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return ReturnResult.success("Ok");
    }


    @ApiOperation("导出报名列表")
    @RequestMapping(value = "/exportStudentReg", method = {RequestMethod.GET, RequestMethod.POST})
    public void exportStudentReg(StudentRegQueryVo studentRegQueryVo, HttpServletRequest request, HttpServletResponse response) throws IOException {
        Principals.Principal principal = Principals.get();
        if (principal == null) {
            throw new BusException("查不到操作人");
        }


        DataPermission dataPermission = this.getDataPermission(request);

        CourseClassQueryVo courseClassQueryVo = new CourseClassQueryVo();
        BeanUtils.copyProperties(courseClassQueryVo, studentRegQueryVo);
        List<CourseClass> courseClassList = courseClassService.findCourseClassList(courseClassQueryVo, dataPermission, "classId", "level");
        Map<Long, CourseClass> courseClassMap = BeanUtils.toMap(courseClassList, "classId");
        Long exportContainPhoneNo = sysRoleResourceService.checkUserHaveResource(principal.id, SysResourceEnum.EXPORT_CONTAIN_PHONE_NO.id);


        Page<StudentRegDetail> regDetailVoPage = studentRegDetailService.findStudentRegByPermissionQuery(dataPermission, studentRegQueryVo, 1, 100000);
        if (regDetailVoPage != null && regDetailVoPage.getRecords() != null) {
            List<StudentRegDetail> studentRegDetailVoList = regDetailVoPage.getRecords();
            List<Long> courseOrderIds = BeanUtils.toList(studentRegDetailVoList, "courseOrderId");
            courseOrderIds = Utils.removeDuplicate(courseOrderIds);
            List<CourseOrderDiscount> courseOrderDiscountList = courseOrderDiscountService.findByCourseOrderIdsDiscountId(courseOrderIds, 0L);
            Map<Long, CourseOrderDiscount> courseOrderDiscountMap = BeanUtils.toMap(courseOrderDiscountList, "courseOrderId");
            Collections.sort(studentRegDetailVoList, new Comparator<StudentRegDetail>() {
                @Override
                public int compare(StudentRegDetail o1, StudentRegDetail o2) {
                    return o1.getStudentId().compareTo(o2.getStudentId());
                }
            });
            SXSSFWorkbook excel = new SXSSFWorkbook();
            SXSSFSheet sheet = excel.createSheet("报名记录");
            String[] titles = new String[]{"学生姓名", "学号", "学生号码", "生源类型", "班主任", "咨询师", "业务组", "班级编号", "班级名称", "年级", "科目", "期名", "段次", "班型",
                    "校区", "教室", "众筹", "开课日期", "上课时间", "教师", "报读日期", "报读开始讲数", "报读结束讲数", "在读开始讲数", "在读结束讲数",
                    "总计金额", "应缴金额", "已缴金额", "退费金额", "报名状态", "缴费时间", "缴费状态", "操作人",  "优惠原因", "优惠备注"};
            Map<Integer, String> regStatusMap = new HashMap<>();
            Map<Integer, String> chargingStatusMap = new HashMap<>();
            Map<Integer, String> studentStateMap = new HashMap<>();
            regStatusMap.put(0, "在读");
            regStatusMap.put(1, "转班");
            regStatusMap.put(2, "退账户");
            regStatusMap.put(3, "退班退费");
            regStatusMap.put(4, "无效");

            chargingStatusMap.put(0, "未缴费");
            chargingStatusMap.put(1, "欠费");
            chargingStatusMap.put(2, "已缴费");

            studentStateMap.put(0, "新生");
            studentStateMap.put(1, "老生");
            studentStateMap.put(2, "续读生");
            int rowIndex = 0;
            int columnIndex = 0;

            SXSSFRow row = sheet.createRow(rowIndex++);
            for (String head : titles) {
                SXSSFCell cell = row.createCell(columnIndex++);
                cell.setCellValue(head);
            }
            Map<String, StudentRegsDetailVo> studentNoCampusPeriodMap = new HashMap<>();
            Set<Long> studentIdSet = new HashSet<>();
            Map<String, Integer> check = new HashMap<>();//key= studentId_classId
            for (StudentRegDetail studentRegDetail : studentRegDetailVoList) {
                studentIdSet.add(studentRegDetail.getStudentId());
                if (studentRegDetail.getRegStatus() == 0) {
                    String key = studentRegDetail.getStudentNo() + "_" + studentRegDetail.getBusTeamId() + "_" + studentRegDetail.getCampusId() + "_" + studentRegDetail.getPeriodId() + "_" + studentRegDetail.getGradeId();
                    StudentRegsDetailVo noCampusPeriodReg = studentNoCampusPeriodMap.get(key);
                    String regKey = studentRegDetail.getStudentId() + "_" + studentRegDetail.getClassId();
                    if (noCampusPeriodReg == null) {
                        noCampusPeriodReg = new StudentRegsDetailVo();
                        BeanUtils.copyProperties(noCampusPeriodReg, studentRegDetail);
                        noCampusPeriodReg.setClassIds(studentRegDetail.getClassId().toString());
                        noCampusPeriodReg.setClassNames(studentRegDetail.getClassName().toString() + "/" + (studentRegDetail.getLectureNum() == null ? 0 : studentRegDetail.getLectureNum()) + "讲");
                        noCampusPeriodReg.setSeniorIds(studentRegDetail.getSeniorId() == null ? "" : studentRegDetail.getSeniorId() + "");
                        noCampusPeriodReg.setSeniorNames(studentRegDetail.getSeniorName());
                        noCampusPeriodReg.setGradeIds(studentRegDetail.getGradeId() + "");
                        noCampusPeriodReg.setGradeNames(studentRegDetail.getGradeName());
                        noCampusPeriodReg.setRegNum(1);
                        noCampusPeriodReg.setPayAmount(studentRegDetail.getPayAmount());
                        check.put(regKey, 1);
                    } else {
                        noCampusPeriodReg.setClassIds(noCampusPeriodReg.getGradeIds() + "," + studentRegDetail.getClassId());
                        noCampusPeriodReg.setClassNames(noCampusPeriodReg.getClassNames() + "," + studentRegDetail.getClassName().toString() + "/" + (studentRegDetail.getLectureNum() == null ? 0 : studentRegDetail.getLectureNum()) + "讲");
                        if (studentRegDetail.getSeniorId() != null) {
                            if (StringUtils.isNotEmpty(noCampusPeriodReg.getSeniorIds()) && !noCampusPeriodReg.getSeniorIds().contains(studentRegDetail.getSeniorId().toString())) {
                                noCampusPeriodReg.setSeniorIds(noCampusPeriodReg.getSeniorIds() + "," + studentRegDetail.getSeniorId());
                                noCampusPeriodReg.setSeniorNames(noCampusPeriodReg.getSeniorNames() + "," + studentRegDetail.getSeniorName());
                            } else {
                                noCampusPeriodReg.setSeniorIds(studentRegDetail.getSeniorId() + "");
                                noCampusPeriodReg.setSeniorNames(studentRegDetail.getSeniorName());
                            }
                        }
                        if (!noCampusPeriodReg.getGradeIds().contains(studentRegDetail.getGradeId().toString())) {
                            noCampusPeriodReg.setGradeIds(noCampusPeriodReg.getGradeIds() + "," + studentRegDetail.getGradeId());
                            noCampusPeriodReg.setGradeNames(noCampusPeriodReg.getGradeNames() + "," + studentRegDetail.getGradeName());
                        }
                        noCampusPeriodReg.setRegNum(noCampusPeriodReg.getRegNum() + (check.containsKey(regKey) ? 0 : 1));
                        noCampusPeriodReg.setPayAmount(noCampusPeriodReg.getPayAmount().add(studentRegDetail.getPayAmount()));
                        noCampusPeriodReg.setSrcTotalAmount(noCampusPeriodReg.getSrcTotalAmount().add(studentRegDetail.getSrcTotalAmount()));


                    }
                    studentNoCampusPeriodMap.put(key, noCampusPeriodReg);
                }

                CourseClass courseClass = courseClassMap.get(studentRegDetail.getClassId());
                Integer level = courseClass == null ? null : courseClass.getLevel();
                columnIndex = 0;
                row = sheet.createRow(rowIndex++);

                SXSSFCell cell = row.createCell(columnIndex++);
                cell.setCellValue(studentRegDetail.getStudentName());

                cell = row.createCell(columnIndex++);
                cell.setCellValue(studentRegDetail.getStudentNo());


                cell = row.createCell(columnIndex++);
                if (exportContainPhoneNo > 0) {
                    cell.setCellValue(studentRegDetail.getStudentPhoneNo());
                }

                cell = row.createCell(columnIndex++);
                cell.setCellValue(studentStateMap.get(studentRegDetail.getStudentState()));

                cell = row.createCell(columnIndex++);
                cell.setCellValue(StringUtils.defaultString(studentRegDetail.getSeniorName()));

                cell = row.createCell(columnIndex++);
                cell.setCellValue(StringUtils.defaultString(studentRegDetail.getCounselorName()));

                cell = row.createCell(columnIndex++);
                cell.setCellValue(studentRegDetail.getBusTeamName());

                cell = row.createCell(columnIndex++);
                cell.setCellValue(studentRegDetail.getClassNo());

                cell = row.createCell(columnIndex++);
                cell.setCellValue(studentRegDetail.getClassName());

                cell = row.createCell(columnIndex++);
                cell.setCellValue(studentRegDetail.getGradeName());


                cell = row.createCell(columnIndex++);
                cell.setCellValue(studentRegDetail.getSubjectName());

                cell = row.createCell(columnIndex++);
                cell.setCellValue(studentRegDetail.getPeriodName());

                cell = row.createCell(columnIndex++);
                cell.setCellValue(studentRegDetail.getSegmentNo() == null ? "" : studentRegDetail.getSegmentNo().toString());

                cell = row.createCell(columnIndex++);
                cell.setCellValue(EnumUtils.getName(ClassLevelEnum.values(), level));


                cell = row.createCell(columnIndex++);
                cell.setCellValue(StringUtils.defaultString(studentRegDetail.getCampusName()));

                cell = row.createCell(columnIndex++);
                cell.setCellValue(StringUtils.defaultString(studentRegDetail.getRoomName()));


                cell = row.createCell(columnIndex++);
                cell.setCellValue(studentRegDetail.getClassType() == null ? "否" : studentRegDetail.getClassType() == 1 ? "是" : "否");

                cell = row.createCell(columnIndex++);
                cell.setCellValue(TimeUtils.date2String(studentRegDetail.getStartCourseTime(), " yyyy-MM-dd"));

                cell = row.createCell(columnIndex++);
                cell.setCellValue(studentRegDetail.getStudyingTime());

                cell = row.createCell(columnIndex++);
                cell.setCellValue(StringUtils.defaultString(studentRegDetail.getTeacherName()));


                cell = row.createCell(columnIndex++);
                cell.setCellValue(TimeUtils.date2String(studentRegDetail.getCreateTime(), " yyyy-MM-dd"));

                cell = row.createCell(columnIndex++);
                cell.setCellValue(studentRegDetail.getInitStartAmount() == null ? 0 : studentRegDetail.getInitStartAmount());

                cell = row.createCell(columnIndex++);
                cell.setCellValue(studentRegDetail.getInitEndAmount() == null ? 0 : studentRegDetail.getInitEndAmount());

                cell = row.createCell(columnIndex++);
                cell.setCellValue(studentRegDetail.getStartAmount() == null || studentRegDetail.getStartAmount() <= 0 ? 0 : studentRegDetail.getStartAmount());

                cell = row.createCell(columnIndex++);
                cell.setCellValue(studentRegDetail.getEndAmount() == null || studentRegDetail.getEndAmount() <= 0 ? 0 : studentRegDetail.getEndAmount());

                cell = row.createCell(columnIndex++);
                cell.setCellType(CellType.NUMERIC);
                cell.setCellValue(Double.parseDouble(BigDecimals.formatBigDecimal(studentRegDetail.getSrcTotalAmount(), "0.00")));

                cell = row.createCell(columnIndex++);
                cell.setCellType(CellType.NUMERIC);
                cell.setCellValue(Double.parseDouble(BigDecimals.formatBigDecimal(studentRegDetail.getTotalAmount(), "0.00")));


                cell = row.createCell(columnIndex++);
                cell.setCellType(CellType.NUMERIC);
                cell.setCellValue(Double.parseDouble(BigDecimals.formatBigDecimal(studentRegDetail.getPayAmount(), "0.00")));

                cell = row.createCell(columnIndex++);
                cell.setCellType(CellType.NUMERIC);
                cell.setCellValue(Double.parseDouble(BigDecimals.formatBigDecimal(studentRegDetail.getRefundAmount(), "0.00")));


                cell = row.createCell(columnIndex++);
                cell.setCellValue(regStatusMap.get(studentRegDetail.getRegStatus()));

                cell = row.createCell(columnIndex++);
                cell.setCellValue(studentRegDetail.getPayTime() == null ? StringUtils.EMPTY : Utils.formatDate(studentRegDetail.getPayTime(), "yyyy-MM-dd HH:mm:ss"));


                cell = row.createCell(columnIndex++);
                cell.setCellValue(chargingStatusMap.get(studentRegDetail.getChargingStatus()));


                cell = row.createCell(columnIndex++);
                cell.setCellValue(StringUtils.defaultString(studentRegDetail.getOperator()));


                cell = row.createCell(columnIndex++);
                cell.setCellValue(StringUtils.defaultString(studentRegDetail.getDiscountReason()));

                CourseOrderDiscount courseOrderDiscount = courseOrderDiscountMap.get(studentRegDetail.getCourseOrderId());
                List<String> discountRemark = new ArrayList<>();
                if (courseOrderDiscount != null) {
                    String imputParams = courseOrderDiscount.getInputParams();
                    if (StringUtils.isNotEmpty(imputParams)) {
                        JSONArray jsonArray = JSONArray.parseArray(imputParams);
                        for (Object jsonObject : jsonArray) {
                            String value = ((JSONObject) jsonObject).getString("value");
                            if (StringUtils.isNotEmpty(value)) {
                                discountRemark.add(value);
                            }
                        }
                    }
                }
                cell = row.createCell(columnIndex++);
                cell.setCellValue(StringUtils.join(discountRemark, ","));

            }
            if (studentIdSet.size() > 0) {
                List<Student> studentList = studentService.findByIds(new ArrayList(studentIdSet), "studentId", "school", "birthday","location","address","remark");
                Map<Long, Student> studentMap = BeanUtils.toMap(studentList, "studentId");
                this.groupStudentDetail(studentMap, studentNoCampusPeriodMap, excel, studentStateMap, exportContainPhoneNo);
            }

            Webs.writeExcel(request, response, excel, "学生报名");

        }


    }

    private SXSSFWorkbook groupStudentDetail(Map<Long, Student> studentMap, Map<String, StudentRegsDetailVo> studentNoCampusPeriodMap, SXSSFWorkbook excel, Map<Integer, String> studentStateMap, Long exportContainPhoneNo) {
        SXSSFSheet sheet = excel.createSheet("学生报读查询");
        String[] titles = new String[]{"学生", "出生年月", "学号", "短信号码", "生源类型", "业务组", "报读校区", "就读学校", "期数", "班主任", "报读年级", "已缴金额",
                "报读科数", "报读明细", "学生地址", "学生详细地址","来源渠道"};
        int rowIndex = 0;
        int columnIndex = 0;
        SXSSFRow row = sheet.createRow(rowIndex++);
        for (String head : titles) {
            SXSSFCell cell = row.createCell(columnIndex++);
            cell.setCellValue(head);
        }
        for (Map.Entry<String, StudentRegsDetailVo> entry : studentNoCampusPeriodMap.entrySet()) {
            StudentRegsDetailVo studentRegsDetailVo = entry.getValue();
            columnIndex = 0;
            row = sheet.createRow(rowIndex++);
            Student student = studentMap.get(studentRegsDetailVo.getStudentId());

            SXSSFCell cell = row.createCell(columnIndex++);
            cell.setCellValue(studentRegsDetailVo.getStudentName());

            cell = row.createCell(columnIndex++);
            cell.setCellValue(student == null ? "" : student.getBirthday() == null ? "" : Utils.formatDate(student.getBirthday(), "yyyy-MM-dd"));


            cell = row.createCell(columnIndex++);
            cell.setCellValue(studentRegsDetailVo.getStudentNo());

            cell = row.createCell(columnIndex++);
            if (exportContainPhoneNo > 0) {
                cell.setCellValue(studentRegsDetailVo.getStudentPhoneNo());
            }

            cell = row.createCell(columnIndex++);
            cell.setCellValue(studentStateMap.get(studentRegsDetailVo.getStudentState()) == null ? "" : studentStateMap.get(studentRegsDetailVo.getStudentState()));

            cell = row.createCell(columnIndex++);
            cell.setCellValue(StringUtils.defaultString(studentRegsDetailVo.getBusTeamName()));

            cell = row.createCell(columnIndex++);
            cell.setCellValue(studentRegsDetailVo.getCampusName() == null ? "" : studentRegsDetailVo.getCampusName());

            cell = row.createCell(columnIndex++);

            cell.setCellValue(student == null ? "" : (student.getSchool() == null ? "" : student.getSchool()));

            cell = row.createCell(columnIndex++);
            cell.setCellValue(studentRegsDetailVo.getPeriodName());

            cell = row.createCell(columnIndex++);
            cell.setCellValue(studentRegsDetailVo.getSeniorNames() == null ? "" : studentRegsDetailVo.getSeniorNames());

            cell = row.createCell(columnIndex++);
            cell.setCellValue(studentRegsDetailVo.getGradeNames() == null ? "" : studentRegsDetailVo.getGradeNames());


            cell = row.createCell(columnIndex++);
            cell.setCellValue(BigDecimals.formatBigDecimal(studentRegsDetailVo.getPayAmount(), "0.00"));

            cell = row.createCell(columnIndex++);
            cell.setCellValue(studentRegsDetailVo.getRegNum());

            cell = row.createCell(columnIndex++);
            cell.setCellValue(studentRegsDetailVo.getClassNames());

            cell = row.createCell(columnIndex++);
            cell.setCellValue(student== null ? "" : student.getLocation());

            cell = row.createCell(columnIndex++);
            cell.setCellValue(student.getAddress() == null ? "" : student.getAddress());

            cell = row.createCell(columnIndex++);
            cell.setCellValue(student==null?"":StringUtils.isEmpty(student.getRemark())?"":student.getRemark());
        }

        return excel;
    }


    @ApiOperation("查询支付结果(post机、在线支付)")
    @RequestMapping("/queryPayResult")
    @ResponseBody
    public DeferredResult<String> queryPayResult(@RequestParam("requestPayId") final Long requestPayId) {
        final String key = String.valueOf(requestPayId);
        final DeferredResult<String> deferredResult = new DeferredResult<>(TimeUnit.SECONDS.toMillis(10));
        deferredResult.onTimeout(() -> {
            if (posPayService.isSuccessPay(requestPayId)) {
                setDeferredResult(deferredResult, "Y");
            } else {
                setDeferredResult(deferredResult, "N");
            }
        });

        deferredResult.onCompletion(() -> {
            synchronized (deferredResultMultimap) {
                deferredResultMultimap.remove(key, deferredResult);
            }
        });

        synchronized (deferredResultMultimap) {
            deferredResultMultimap.put(key, deferredResult);
        }

        return deferredResult;
    }

    public static void setDeferredResult(DeferredResult<String> deferredResult, String result) {
        deferredResult.setResult(result);
    }



    @ApiOperation("查询学生在某个班的出勤状态")
    @RequestMapping(value = "/queryAttendOfStudent", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<AttendClassVo> queryAttendOfStudent(@RequestParam(value = "regId") Long regId) {

        StudentReg studentReg = studentRegService.findById(regId);
        List<ClassLecture> regClassLectureList = classLectureService.findRegClassLectureByRegId(studentReg);
        List<Long> classLectureIds = BeanUtils.toList(regClassLectureList, "classLectureId");
        Map<Long, ClassLecture> classLectureId2ClassLecture = BeanUtils.toMap(regClassLectureList, "classLectureId");
        List<AttendClassRecord> attendClassRecordList = attendClassRecordService.findByRegIdClassLectureIds(studentReg.getRegId(), classLectureIds);

        List<AttendClassVo> attendOfStudentVoList = new ArrayList<>(attendClassRecordList.size());
        for (AttendClassRecord attendClassRecord : attendClassRecordList) {
            AttendClassVo attendOfStudentVo = new AttendClassVo();
            attendOfStudentVo.setAttendClassRecordId(attendClassRecord.getAttendClassRecordId());
            attendOfStudentVo.setAttendanceStatus(attendClassRecord.getIsAttendance() == 1 ? attendClassRecord.getAttendanceStatus() : 9);
            attendOfStudentVo.setClassLectureId(attendClassRecord.getClassLectureId());
            attendOfStudentVo.setShiftStatus(attendClassRecord.getShiftStatus());
            ClassLecture classLecture = classLectureId2ClassLecture.get(attendClassRecord.getClassLectureId());
            attendOfStudentVo.setLectureNo(classLecture.getLectureNo());
            attendOfStudentVoList.add(attendOfStudentVo);
        }
        return ReturnResult.success(attendOfStudentVoList);
    }


    @ApiOperation("查询学生在读多个班的出勤状态")
    @RequestMapping(value = "/queryAttendOfStudentRegs", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<AttendClassVo> queryAttendOfStudent(@RequestParam(value = "regIds") List<Long> regIds) {

        Map<Long,List<AttendClassVo>> result=new HashMap<>(regIds.size());
        List<StudentReg> studentRegList=studentRegService.findByIds(regIds);
        Map<Long,List<ClassLecture>> map=classLectureService.findRegClassLectureByRegs(studentRegList);
        List<Long> allClassLectureIds=new ArrayList<>();
        for (Map.Entry<Long,List<ClassLecture>> entry:map.entrySet()){
            allClassLectureIds.addAll(BeanUtils.toList(entry.getValue(),"classLectureId"));
        }
        List<AttendClassRecord> allAttendClassRecordList = attendClassRecordService.findByRegIdsClassLectureIds(regIds, allClassLectureIds);
        Map<Long, List<AttendClassRecord>> regAttendClassRecordMap = BeanUtils.toGroup(allAttendClassRecordList, "regId");

        for (StudentReg studentReg:studentRegList){
            List<ClassLecture> regClassLectureList = map.get(studentReg.getRegId());
            Map<Long, ClassLecture> classLectureId2ClassLecture = BeanUtils.toMap(regClassLectureList, "classLectureId");
            List<AttendClassRecord> attendClassRecordList=regAttendClassRecordMap.get(studentReg.getRegId());
            List<AttendClassVo> attendOfStudentVoList = new ArrayList<>(attendClassRecordList.size());
            for (AttendClassRecord attendClassRecord : attendClassRecordList) {
                AttendClassVo attendOfStudentVo = new AttendClassVo();
                attendOfStudentVo.setAttendClassRecordId(attendClassRecord.getAttendClassRecordId());
                attendOfStudentVo.setAttendanceStatus(attendClassRecord.getIsAttendance() == 1 ? attendClassRecord.getAttendanceStatus() : 9);
                attendOfStudentVo.setClassLectureId(attendClassRecord.getClassLectureId());
                attendOfStudentVo.setShiftStatus(attendClassRecord.getShiftStatus());
                ClassLecture classLecture = classLectureId2ClassLecture.get(attendClassRecord.getClassLectureId());
                attendOfStudentVo.setLectureNo(classLecture.getLectureNo());
                attendOfStudentVoList.add(attendOfStudentVo);
            }
            result.put(studentReg.getRegId(),attendOfStudentVoList);
        }

        return ReturnResult.success(result);
    }

    @ApiOperation("保存调班")
    @RequestMapping(value = "/saveShiftClass", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<Void> saveShiftClass(@RequestParam(value = "fromAttendClassRecordId") Long fromAttendClassRecordId, @RequestParam("destClassLectureId") Long destClassLectureId, String remark) {
        shiftClassRecordService.saveShiftClass(fromAttendClassRecordId, destClassLectureId, remark, Principals.get());
        return ReturnResult.success("OK");
    }

    @ApiOperation("撤销pos机扫码")
    @RequestMapping(value = "/cancelPosScan", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ReturnResult<Void> cancelPosScan(@RequestParam(value = "courseOrderId") Long courseOrderId ) {
        posPayService.cancel(courseOrderId);
        return ReturnResult.success("OK");
    }


}